package com.vrp3d.service.impl;

import com.vrp3d.common.enums.CacheExceptionEnum;
import com.vrp3d.common.exceptions.RedisStorageException;
import com.vrp3d.service.RedisService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;

/**
 * Redis的基础服务
 *
 * @author vrp3d
 */
@Service
public class RedisServiceImpl implements RedisService {

    @Autowired
    private RedisTemplate<String, String> redisUtils;

    /**
     * 保存数据到redis中
     *
     * @param [key, data]
     * @return void
     * @author huangxiong
     * @date 2018/11/22 17:53
     */
    @Override
    public void putCache(String key, String data) {
        /*
         * 1.校验key,data的合法性,不符合条件时给出提示
         * 2.利用RedisTemplate存入redis中
         */
        if (StringUtils.isBlank(key)) {
            throw new RedisStorageException(CacheExceptionEnum.KEY_NULL);
        }
        if (StringUtils.isBlank(data)) {
            throw new RedisStorageException(CacheExceptionEnum.VALUE_NULL);
        }
        redisUtils.execute((RedisCallback<Boolean>) redisConnection -> {
            RedisSerializer<String> stringSerializer = redisUtils.getStringSerializer();
            redisConnection.set(key.getBytes(), stringSerializer.serialize(data));
            return true;
        });
    }

    /**
     * 保存数据到redis中,在特定时间之后自动销毁数据
     *
     * @param [key, data, expireTime]
     * @return void
     * @author huangxiong
     * @date 2018/11/22 17:53
     */
    @Override
    public void putCacheWithExpireTime(String key, String data, int expireTime) {
        /*
         * 1.校验key,data,expireTime的合法性,不符合条件时给出提示
         * 2.利用利用RedisTemplate存入redis中
         */
        if (StringUtils.isBlank(key)) {
            throw new RedisStorageException(CacheExceptionEnum.KEY_NULL);
        }
        if (StringUtils.isBlank(data)) {
            throw new RedisStorageException(CacheExceptionEnum.VALUE_NULL);
        }
        if (expireTime < 1) {
            throw new RedisStorageException(CacheExceptionEnum.EXPIRE_TIME_ERROR);
        }
        redisUtils.execute((RedisCallback<Boolean>) redisConnection -> {
            redisConnection.setEx(key.getBytes(), expireTime, data.getBytes());
            return true;
        });
    }

    /**
     * 删除key
     *
     * @param [key]
     * @return void
     * @author huangxiong
     * @date 2018/11/22 17:54
     */
    @Override
    public void remove(String key) {
        /*
         * 1.校验key的合法性,不符合条件时给出提示
         * 2.利用利用RedisTemplate删除redis中数据
         */
        if (StringUtils.isBlank(key)) {
            throw new RedisStorageException(CacheExceptionEnum.KEY_NULL);
        }
        redisUtils.delete(key);
    }

    /**
     * 根据key查询数据
     *
     * @param [key]
     * @return java.lang.String
     * @author huangxiong
     * @date 2018/11/22 17:54
     */
    @Override
    public String query(String key) {
        /*
         * 1.校验key的合法性,不符合条件时给出提示
         * 2.利用利用RedisTemplate查询redis中数据
         * 3.判断返回值是否为空,返回结果
         */
        if (StringUtils.isBlank(key)) {
            throw new RedisStorageException(CacheExceptionEnum.KEY_NULL);
        }
        byte[] result = redisUtils.execute((RedisCallback<byte[]>) redisConnection -> {
            RedisSerializer<String> stringSerializer = redisUtils.getStringSerializer();
            return redisConnection.get(stringSerializer.serialize(key));
        });
        if (result != null && result.length > 0) {
            return redisUtils.getStringSerializer().deserialize(result);
        } else {
            return null;
        }
    }

    @Override
    public List<String> queryWithPrefix(String key) {
        /*
         * 1.校验key的合法性,不符合条件时给出提示
         * 2.利用利用RedisTemplate查询redis中数据
         * 3.判断返回值是否为空,返回结果
         */
        if (StringUtils.isBlank(key)) {
            throw new RedisStorageException(CacheExceptionEnum.KEY_NULL);
        }
        key = key + "*";
        Set<String> keys = redisUtils.keys(key);
        if (keys != null) {
            return new ArrayList<>(keys);
        }
        return null;
    }

    @Override
    public Long queryExpirationTime(String key) {
        /*
         * 1.校验key的合法性,不符合条件时给出提示
         * 2.利用利用RedisTemplate查询redis中数据
         * 3.判断返回值是否为空,返回结果
         */
        if (StringUtils.isBlank(key)) {
            throw new RedisStorageException(CacheExceptionEnum.KEY_NULL);
        }
        byte[] result = redisUtils.execute((RedisCallback<byte[]>) redisConnection -> {
            RedisSerializer<String> stringSerializer = redisUtils.getStringSerializer();
            return redisConnection.get(stringSerializer.serialize(key));
        });
        if (result != null && result.length > 0) {
            return redisUtils.getExpire(key);
        } else {
            return null;
        }
    }

    /**
     * 保存的数据自增
     *
     * @param [key]
     * @return long
     * @author huangxiong
     * @date 2018/11/22 17:55
     */
    @Override
    public long autoIncr(String key) {
        /*
         * 1.校验key的合法性,不符合条件时给出提示
         * 2.利用利用RedisTemplate实现key对应的值自增
         * 3.判断返回值是否为空,返回数据
         */
        if (StringUtils.isBlank(key)) {
            throw new RedisStorageException(CacheExceptionEnum.KEY_NULL);
        }
        Long result = redisUtils.execute((RedisCallback<Long>) redisConnection -> redisConnection.incr(key.getBytes()));
        if (result != null) {
            return result;
        }
        return 0;
    }

    /**
     * 自增,生命周期以最近一次登录时间为准
     *
     * @param [key, time]
     * @return long
     * @author huangxiong
     * @date 2018/11/22 17:55
     */
    @Override
    public long incrOnExpireKey(String key, Integer time) {
        /*
         * 1.校验key,time的合法性,不符合条件时给出提示
         * 2.利用利用RedisTemplate实现key对应的值自增在对应的时间后销毁
         * 3.判断返回值是否为空,返回数据
         */
        if (StringUtils.isBlank(key)) {
            throw new RedisStorageException(CacheExceptionEnum.KEY_NULL);
        }
        if (time == null) {
            throw new RedisStorageException(CacheExceptionEnum.TIME_NULL);
        }
        Long result = redisUtils.execute((RedisCallback<Long>) connection -> {
            Long incrResult = connection.incr(key.getBytes());
            connection.expire(key.getBytes(), time);
            return incrResult;
        });
        if (result != null) {
            return result;
        }
        return 0;
    }

    /**
     * 判断key是否存在
     *
     * @param [key]
     * @return boolean
     * @author huangxiong
     * @date 2018/11/22 17:55
     */
    @Override
    public boolean exits(String key) {
        /*
         * 1.校验key的合法性,不符合条件时给出提示
         * 2.利用利用RedisTemplate查询key是否存在
         * 3.判断返回值是否为空,返回数据
         */
        if (StringUtils.isBlank(key)) {
            throw new RedisStorageException(CacheExceptionEnum.KEY_NULL);
        }
        Boolean result = redisUtils.execute((RedisCallback<Boolean>) connection -> connection.exists(key.getBytes()));
        if (result != null) {
            return result;
        }
        return false;
    }

    /**
     * 对特定的key增加特定的值
     *
     * @param [key, value]
     * @return long
     * @author huangxiong
     * @date 2018/11/22 16:37
     */
    @Override
    public long incrByKey(String key, Integer value) {
        /*
         * 1.判断key和value的合法性,不符合时给出提示
         * 2.利用利用RedisTemplate给对应key的值增加value
         * 3.判断返回值是否为空,返回数据
         */
        if (StringUtils.isBlank(key)) {
            throw new RedisStorageException(CacheExceptionEnum.KEY_NULL);
        }
        if (value == null) {
            throw new RedisStorageException(CacheExceptionEnum.VALUE_NULL);
        }
        Long result = redisUtils.execute((RedisCallback<Long>) redisConnection -> redisConnection.incrBy(key.getBytes(), value));
        if (result != null) {
            return result;
        }
        return 0;
    }
}
